<?php

/**
 * Work.php
 * 
 * WorkPHP框架基类,用于被其它类继承。
 * @author wang <wang@fvzone.com>
 * @copyright  Copyright (c) 2010 Fire vision Software Studio
 * @link http://www.fvzone.com
 * @license New BSD License.{@link http://www.opensource.org/licenses/bsd-license.php}
 * @version $Id: Work.php 1.0 2010-10-18 21:49:01Z wang $
 * @package core
 * @since 1.0
 */

defined('IN_WORK') or exit('Authorization error');

abstract class Work
{
    /**
     * @var array 载入文件标识
     */
    protected static $_imported = array();

    /**
     * @var array 对象注册表
     */
    protected static $_objected = array();

    /**
     * @var array 框架核心文件
     */
    public static $_classes = array(
        'work'              => 'core.work',
        'trace'             => 'core.trace',
        'config'            => 'core.config',
        'request'           => 'core.request',
        'view'              => 'core.view',
        'log'               => 'core.log',
        'model'             => 'core.model',
        'widget'            => 'core.widget',
        'component'         => 'core.component',
        'controller'        => 'core.controller',
        'exception_work'    => 'exception.work',
        'db_mysqli'         => 'db.mysqli',
        'db_mysql'          => 'db.mysql',
        'db_pdo'            => 'db.pdo',
        'db_sqlite'         => 'db.sqlite',
        'db_oracle'         => 'db.oracle',
        'db_postgres'       => 'db.postgres',
        'db_mssql'          => 'db.mssql',
        'db_mongo'          => 'db.mongo'
    );

	/**
	 * 实例化视图
	 * 本函数相当于class View 单例模式的实例化
	 *
	 * @return View
	 */
	public function view()
    {
        return $this->view = self::instance('View');
	}

	/**
	 * 单例模式实例化一个Model对象
	 * 初次实例化某Model后, 当第二次实例化时则直接调用初次实现化的结果(object)
	 *
	 * @param string $table_name 	所要实例化的Modle名称
	 * @return object				实例化后的对象
	 */
	public static function model($table)
    {
		//分析model名, abc_abc 转换成 Abc_Abc
        $model = str_replace(' ', '_', ucwords(str_replace('_', ' ', $table))).'_Model';
		return self::instance($model);
	}
    
    /**
     * 加载视图文件的挂件(widget)
     * 加载挂件内容，一般用在视图内容中(view)
     *
     * @param string  $widget_name 所要加载的widget名称,注没有后缀名
     * @param array   $params 参数 如array('id'=>23)
     * @return boolean
     */
    public static function widget($name, $params = null)
    {
        //分析widget名称
        $class  = ucfirst(strtolower($name)) . '_Widget';
        $object = Work::instance($class);
        $object->before();
        $object->render($params);
    }
    
    /**
     * 配置文件读取设置
     *
     * 本方法是Config类的单列对象，为方便读取配置文件，并且读取后的文件数据会被存放在Config对象中
     * 使用方法: Work::config()->view, Work::config()->db['driver']
     *
     * @return Config
     */
    public static function config($value = null, $default = null)
    {
        $config = self::instance('Config');
        if (empty($value)) 
        {
            return $config;
        }
        return $config->get($value, $default);
    }

	/**
	 * 项目文件的自动加载
	 * 
	 * workPHP系统自动加载核心类库文件(core目录内的文件)及运行所需的controller文件、model文件、widget文件等
	 * 
	 * 注:并非程序初始化时将所有的controller,model等文件都统统加载完,再执行其它.理解本函数前一定要先理解autoload()的作用.
	 * 当程序运行时发现所需的文件没有找到时,autoload()才会被激发,按照autoload()的程序设计来完成对该文件的加载
	 * 
	 * @param string $class_name 所需要加载的类的名称,注:不含后缀名
	 * @return void
	 */
	public static function autoload($class)
    {
        //类已经定义
		if (class_exists($class, false) || interface_exists($class, false))
			return;

        //全部小写字母
        $_class = strtolower($class);
        
        //加载框架核心，必须在前面
        if(isset(self::$_classes[$_class]))
        {
            import('work.'.self::$_classes[$_class]);
            return;
        }
        
        //切开数据
        $parts    = explode('_', $_class);

        //获取下划线最后一个字符串，比如abc_abc_controller，将得到controller
        $workshop = array_pop($parts);

        //需要分析的后缀定义
        $suffix = array('controller', 'model', 'widget');
     
        //当前组件名称
        $component = Request::component();

        //载入控制器，模型，部件
        if (in_array($workshop, $suffix))
        {
            //获取数组的倒数第二个参数
            $two       = array_pop($parts);

            //去掉工作域，比如controller或者widget和model
            $filename  = str_replace('_'.$workshop, '', $_class);

            //子目录加载目前只支持控制器
            $subfolder = ($workshop == 'controller') ? join('.', $parts) : null;
            $class = $subfolder ? $subfolder.'.'.$filename : $filename;

            //组件开发模式
            if ($component && import("components.{$component}.{$workshop}s.{$class}"))
                return;

            //普通开发模式
            else if(import("public.{$workshop}s.{$class}"))
                return;

            else
               throwException("{$workshop} import file {$class} Not Found!");
        }

        //当前组件扩展库
        elseif (import("components.{$component}.libraries.{$class}"))
            return;

        //应用扩展库
        elseif (import('public.libraries.'.$class))
            return;

        //框架核心扩展库
        elseif (import('work.libraries.'.$class))
            return;

        //没有找到相关的类
        else
            throwException("Automatically import file {$class} Not Found!");
	}
    
    /**
	 * 从指定的目录加载的文件
     *
     * 文件名以"."分割
	 *
	 * @param   string   $key    目录名称 + 文件名
	 * @param   string   $base   起始路径
	 * @return  boolean
	 */
	public static function import($key, $base = null)
	{
		if (!isset(self::$_imported[$key]))
        {
            $success	= false;
            $parts		= explode('.', $key);
            $root		= array_shift($parts);
            $class		= array_pop($parts);
            $base		= ($base == '') ? APP_DIR : $base;
            $path		= join(DS, $parts);
            
            //导入的是框架
            if ($root == 'work')
            {
                $base = WORK_DIR;
            }
            //导入的是公共组件
            elseif ($root == 'public')
            {
                $base = PUBLIC_DIR;
            }
            //导入的是组件
            elseif ($root == 'components')
            {
                $base = COMPONENT_DIR;
            }
            //导入其他库
            else
            {
                $base = $base.$root;
            }
 
            //最后的组合文件数据
            $file = $base.$path.DS.$class.'.php';
            //如果文件存在，则导入
            if (is_file($file))
            {
                $success = (bool) include_once $file;
            }
            //添加导入状态，找到标记true没有找到标记false
            self::$_imported[$key] = $success;
		}
        return self::$_imported[$key];
	}

	/**
	 * 返回唯一的实例(单例模式)
	 * 
	 * 程序开发中,model,module, widget, 或其它类在实例化的时候,将类名登记到workPHP注册表数组($_objects)中,当程序再次实例化时,直接从注册表数组中返回所要的对象.
	 * 若在注册表数组中没有查询到相关的实例化对象,则进行实例化,并将所实例化的对象登记在注册表数组中.此功能等同于类的单例模式.
	 * 
	 * 注:本方法只支持实例化无须参数的类.如$object = new pagelist(); 不支持实例化含有参数的.
	 * 如:$object = new pgelist($total_list, $page);
	 *
	 * <code>
	 * $object = Work::instance('pagelist');
	 * </code>
	 * 
	 * @param string  $class  要获取的对象的类名字
	 * @return object 返回对象实例
	 */
	public static function instance($class)
    {
		$key = strtolower($class);
		
		if (isset(self::$_objected[$key]))
			return self::$_objected[$key];
        
		return self::$_objected[$key] = new $class();
	}

    /**
     * 记录和统计时间(微秒)
     *
     * @param string  $start  开始标识
     * @param string  $end  结束标识
     * @param string  $dec  小数点位数
     * @return string
     */
    public static function time($start, $end = null, $dec = 3)
    {
        static $_info = array();
        // 统计时间
        if (!empty($end)) 
        {
            if (!isset($_info[$end])) 
            {
                $_info[$end] = microtime(true);
            }
            return number_format(($_info[$end] - $_info[$start]), $dec);

        //记录时间
        } 
        else
        { 
            $_info[$start] = microtime(true);
        }
    }

	/**
	 * 自动变量设置
	 * 程序运行时自动完成类中作用域为protected及private的变量的赋值 。

	 * @param string $name 属性名
	 * @param string $value 属性值
	 * @return void
	 */
	 public function __set($name, $value) 
     {
	 	if (property_exists($this, $name))
        {
	 		$this->$name = $value;
	 	}	 	
	 }
	 
	 /**
	  * 自动变量获取
	  * 程序运行时自动完成类中作用域为protected及private的变量的获取。
	  *
	  * @param string $name 属性名
	  * @return mixed
	  */
	 public function __get($name)
     {
	 	return isset($this->$name) ? $this->$name : false;
	 }
	 
	 /**
	  * 函数: __call()
	  * 用于处理类外调用本类不存在的方法时的信息提示
	  *
	  * @param string $method 方法名称
	  * @param string $args   参数名称
	  * @return string
	  */
	 public function __call($method, array $args)
     {
	 	echo 'Method:'.$method.'() is not exists in Class:'.get_class($this).'!<br/>The args is:<br />';
	 	foreach ($args as $value)
        {	 		
	 		echo $value, '<br />';
	 	}
	 }
}

/**
 * 调用SPL扩展,注册__autoload()函数
 */
spl_autoload_register(array('Work','autoload'));

/**
 * 导入文件的函数
 */
function import($key, $base = null)
{
    return Work::import($key, $base);
}

/**
 * 用户手动触发异常函数
 */
function throwException($message)
{
    throw new Exception_Work($message, 'custom');
}